#pragma once

#include <iostream>
#include <string>
#include <memory>
#include <sys/select.h>
#include <unistd.h>
#include "Socket.hpp"

using namespace net_work;

const int gdefaultport = 8888;
const int gdefaultbacklog = 5;
const int num = sizeof(fd_set) * 8;

class SelectServer
{
private:
    void HandlerEvent(fd_set &rfds)
    {
        for (int i = 0; i < num; ++i)
        {
            if (_rfds_array[i] == nullptr)
                continue;

            int fd = _rfds_array[i]->GetSockfd();
            if (FD_ISSET(fd, &rfds))
            {
                // 新链接到来
                if (fd == _listensock->GetSockfd())
                {
                    std::string clientip;
                    uint16_t clientport;
                    Socket *sock = _listensock->AcceptConnection(&clientip, &clientport);
                    if (!sock)
                    {
                        std::cout << "AcceptConnection error" << std::endl;
                        continue;
                    }

                    std::cout << "获取新链接成功，clientip: " << clientip << ", clientport: " << clientport << std::endl;
                    int i = 0;
                    for (i = 0; i < num; ++i)
                    {
                        if (_rfds_array[i] == nullptr)
                        {
                            _rfds_array[i] = sock;
                            break;
                        }
                    }
                    if(i == num)
                    {
                        std::cout << "server is full..." << std::endl;
                        sock->CloseSocket();
                        delete sock;
                    }
                }
                else // 读事件就绪
                {
                    std::cout << "读事件就绪" << std::endl;
                    std::string buffer;
                    int size = 1024;
                    bool ret = _rfds_array[i]->Recv(&buffer, size);
                    if(ret)
                    {
                        std::cout << "client: " << buffer << std::endl; 
                    }
                    else
                    {
                        std::cout << "读事件失败" << std::endl;
                        _rfds_array[i]->CloseSocket();
                        delete _rfds_array[i];
                        _rfds_array[i] = nullptr;
                    }
                }
            }
        }
    }

public:
    SelectServer(int port = gdefaultport) : _listensock(new TcpSockfd()), _port(port), _isrunning(false)
    {
    }

    void InitServer()
    {
        _listensock->BuildListenSocketMethod(_port, defaultbacklog);
        std::cout << "创建套接字成功" << std::endl;
        for (int i = 0; i < num; ++i)
            _rfds_array[i] = nullptr;
        _rfds_array[0] = _listensock.get();
    }

    void Loop()
    {
        _isrunning = true;
        while (true)
        {
            // 读集合
            fd_set rfds;
            FD_ZERO(&rfds);
            // 遍历数组：1.找最大的fd 2.将合法的fd添加到rfds集合中
            int maxfd = 0;
            for (int i = 0; i < num; ++i)
            {
                if (_rfds_array[i] == nullptr)
                    continue;
                else
                {
                    maxfd = max(maxfd, _rfds_array[i]->GetSockfd());
                    FD_SET(_rfds_array[i]->GetSockfd(), &rfds);
                }
            }
            PrintDebug();
            struct timeval timeout;
            timeout = {0, 0};

            // int ret = select(maxfd + 1, &rfds, nullptr, nullptr, &timeout);
            int ret = select(maxfd + 1, &rfds, nullptr, nullptr, nullptr);
            if (ret < 0)
            {
                std::cout << "select error" << std::endl;
                break;
            }
            else if (ret == 0)
            {
                std::cout << "select timeout, last time: " << timeout.tv_sec << " " << timeout.tv_usec << std::endl;
            }
            else
            {
                std::cout << "select success!!!" << std::endl;
                HandlerEvent(rfds);
            }
            sleep(1);
        }
        _isrunning = false;
    }

    void PrintDebug()
    {
        for (int i = 0; i < num; ++i)
        {
            if (_rfds_array[i] == nullptr)
                continue;
            else
                std::cout << _rfds_array[i]->GetSockfd() << " ";
        }
        std::cout << std::endl;
    }

private:
    std::unique_ptr<Socket> _listensock;
    uint16_t _port;
    bool _isrunning;
    Socket *_rfds_array[num];
};